import { HTMLAttributes, useState, type FC } from 'react';
import classNames from 'classnames';
import { useCss, useEffectOnce, useEnsuredForwardedRef, useMount, useUpdateEffect } from 'react-use';
import { animated, useSpring, useSpringRef } from '@react-spring/web';
import { nagDefaultProps } from './defaultProps';
import type { NagOptions } from './type';
import NagTitle from './NagTitle';
import getStyleAttr from '../_util/getStyleAttr';
import NagGroup from './NagGroup';

export interface NagProps extends NagOptions, Omit<HTMLAttributes<HTMLDivElement>, 'color'> {}

interface NagInterface extends FC<NagProps> {
  Title: typeof NagTitle;
  Group: typeof NagGroup;
}

const Nag: NagInterface = (props) => {
  const {
    className,
    ui,
    active,
    duration,
    fixed,
    overlay,
    color,
    inverted,
    size,
    children,
    forwardedRef,
    style,
    onClose,
    ...nagProps
  } = props;
  const springRef = useSpringRef();
  const ensuredForwardRef = useEnsuredForwardedRef<HTMLDivElement>(forwardedRef!);
  const [isActive, setIsActive] = useState(active);
  const [styles, setStyles] = useState<any>(style);
  const relative = useCss({ position: 'relative' });

  const spring = useSpring({
    ref: springRef,
    height: 0,
    paddingTop: 0,
    paddingBottom: 0,
    config: { duration },
  });

  useEffectOnce(() => {
    if (active) {
      setStyles({ ...style, display: 'block' });
    }
  });

  useUpdateEffect(() => {
    if (!overlay) {
      setIsActive(active);
    }
  }, [active]);

  useUpdateEffect(() => {
    setStyles({ ...style, ...spring, overflow: 'hidden', display: 'block' });
    const el = ensuredForwardRef.current;
    const pt = Number(getStyleAttr(el, 'padding-top'));
    const pb = Number(getStyleAttr(el, 'padding-bottom'));
    if (isActive) {
      setTimeout(() => {
        springRef.current.at(0)?.start({
          from: {
            height: 0,
            paddingTop: 0,
            paddingBottom: 0,
          },
          to: {
            height: el.scrollHeight + pt + pb,
            paddingTop: pt,
            paddingBottom: pb,
          },
          config: { duration },
        });
        setTimeout(() => {
          setStyles({ ...style, display: 'block' });
        }, (duration || 0) + 20);
      }, 25);
    } else {
      springRef.current.at(0)?.start({
        from: {
          height: el.scrollHeight,
          paddingTop: pt,
          paddingBottom: pb,
        },
        to: {
          height: 0,
          paddingTop: 0,
          paddingBottom: 0,
        },
        config: { duration },
      });
      setTimeout(() => {
        setStyles(style);
      }, (duration || 0) + 20);
    }
  }, [isActive]);

  const handleClose = () => {
    if (onClose) {
      onClose();
    } else {
      setIsActive(false);
    }
  };

  useMount(() => {
    const parentEl = ensuredForwardRef.current.parentElement;
    if (overlay && getStyleAttr(parentEl, 'position') !== 'relative') {
      ensuredForwardRef.current.parentElement?.classList.add(relative);
    }
  });

  return (
    <animated.div
      ref={ensuredForwardRef}
      className={classNames({ ui, inverted }, color, fixed, { fixed }, overlay, { overlay }, size, 'nag', className)}
      style={styles}
      {...nagProps}
    >
      {children}
      <i className="close icon" onClick={handleClose}></i>
    </animated.div>
  );
};

Nag.displayName = 'Nag';
Nag.defaultProps = nagDefaultProps;

Nag.Title = NagTitle;
Nag.Group = NagGroup;

export default Nag;
